#pragma once
#ifndef _KH_CORE_COMMON_H
#define _KH_CORE_COMMON_H

// Fix for IntelliSense error

#if defined(_DEBUG) && defined(KH_CORE_DEBUG_ALLOC)
#  define _CRTDBG_MAP_ALLOC
#  include <stdlib.h>
#  include <crtdbg.h>
#endif

#ifdef _MSC_VER
#  define KH_PLATF_WIN 1
#  define KH_PLATF_MAC 0
#  define KH_PLATF_LINUX 0
#else
#  error Unsupported platform
#endif

#ifdef _MSC_VER
#  if _MSC_VER < 1600
#    error "Unsupport Visual C++ Version"
#  endif
#  define KH_NO_VTABLE __declspec(novtable)
#else
#  define KH_NO_VTABLE  
#endif

#define KH_INTERFACE __interface

#ifdef KH_CORE_SOURCE
#  define KH_CORE_API __declspec(dllexport)
#else
#  define KH_CORE_API __declspec(dllimport)
#endif

#include <new>

#define WIN32_LEAN_AND_MEAN
#include <boost/python.hpp>
#include <stackless_api.h>
#include <stackless.h>
#include <boost/smart_ptr.hpp>
#include <boost/smart_ptr/make_shared.hpp>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
#pragma warning(push)
#pragma warning(disable: 4244)
// warning C4244: 'argument' : conversion from '__int64' to 'long', possible loss of data
#include <boost/thread.hpp>
#pragma warning(pop)
//#include <boost/asio.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/threadpool.hpp>
#include <exception>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <hash_map>
#include <iostream>
#include <fstream>

// This template specialization allows us to use a handle to PyChannelObject
namespace boost { namespace python {

template <>
struct base_type_traits<PyChannelObject>
{
    typedef PyObject type;
};

template <>
struct base_type_traits<PyTaskletObject>
{
    typedef PyObject type;
};

typedef str bytes;

namespace converter {

BOOST_PYTHON_BUILTIN_OBJECT_TRAITS(Channel);
BOOST_PYTHON_BUILTIN_OBJECT_TRAITS(Tasklet);

} // namespace converter

}} // namespace boost::python

namespace kharlia {

// basic types
typedef unsigned char uchar;
typedef unsigned char byte;
typedef unsigned short ushort;
typedef unsigned long ulong;
typedef unsigned int uint;
typedef signed __int8 sint8;
typedef signed __int16 sint16;
typedef signed __int32 sint32;
typedef signed __int64 sint64;
typedef unsigned __int8 uint8;
typedef unsigned __int16 uint16;
typedef unsigned __int32 uint32;
typedef unsigned __int64 uint64;

// Boost.Python
namespace py = boost::python;
using namespace py;
//using py::type_info;
static const slice_nil nil = slice_nil(); // prefer nil over _

// common usings
using boost::scoped_ptr;
using boost::scoped_array;
using boost::shared_ptr;
using boost::shared_array;
using boost::intrusive_ptr;
using boost::weak_ptr;
using boost::make_shared;
using boost::allocate_shared;
using boost::format;
using boost::wformat;
using boost::enable_shared_from_this;
using boost::noncopyable;

// helper macros
#define KH_DEF_READONLY_BY_VALUE(name, member) add_property(name, make_getter((member), return_value_policy<return_by_value>()))
#define KH_DEF_READWRITE_BY_VALUE(name, member) add_property(name, make_getter((member), return_value_policy<return_by_value>()), \
                                                                   make_setter((member), return_value_policy<return_by_value>()))

} // namespace Kharlia

// Common includes
#include <Kharlia/Core/Exceptions.h>

namespace kharlia { namespace core {

class FLogger;

// kharlia.__core
KH_CORE_API object GetInnerModuleAttr(str);
// kharlia._core, this module
KH_CORE_API object GetModuleAttr(str);
KH_CORE_API void SetModuleAttr(str, object);
// Retrieve main logger for this module, named 'core'
KH_CORE_API shared_ptr<FLogger> const& GetMainLogger();

inline bool IsCurrentTaskletMain() {
    PyThreadState* ts = PyThreadState_GET();
    return ts->st.main == ts->st.current;
}

inline object GetCurrentTasklet() {
    return object(handle<>(PyStackless_GetCurrent()));
}

// Stat reporting helpers

inline double StatGetClock() {
#if KH_PLATF_WIN
    __int64 time;
    static __int64 freq;
    static bool hasFreq =
        QueryPerformanceFrequency((LARGE_INTEGER*)&freq)?
            __noop():
            throw RuntimeError("Windows QueryPerformanceCounter not supported");
    QueryPerformanceCounter((LARGE_INTEGER*)&time);
    return double(time) / double(freq);
#else
#error
#endif
}

}} // namespace Kharlia

#endif